﻿using System.Text;
using Admin.ApplicationLib.Entities;
using Admin.ApplicationLib.Repositories;
using Admin.ApplicationLib.Specifications;
using Admin.CommonLib.Constants;
using Admin.CommonLib.Models.Role;
using Admin.CommonLib.Models.User;
using AutoMapper;
using Swimj.CommonLib.Base;
using Swimj.CommonLib.Constants;
using Swimj.Core.Providers;
using Swimj.Core.Securities;

namespace Admin.ApplicationLib.Services
{
    public class RoleService : IRoleService
    {
        private readonly IRoleRepository _roleRepository;
        private readonly IUserRepository _userRepository;
        private readonly ISecurityUser _securityUser;
        private readonly IDateTimeProvider _dateTimeProvider;
        private readonly IExcelProvider _excelProvider;
        private readonly IMapper _mapper;

        public RoleService(IRoleRepository roleRepository,
            IUserRepository userRepository,
            ISecurityUser securityUser,
            IDateTimeProvider dateTimeProvider,
            IExcelProvider excelProvider,
            IMapper mapper)
        {
            _roleRepository = roleRepository;
            _userRepository = userRepository;
            _securityUser = securityUser;
            _dateTimeProvider = dateTimeProvider;
            _excelProvider = excelProvider;
            _mapper = mapper;
        }

        public async Task<PaginatedResult<RoleInfoResponseDto>> QueryRolesByPageAsync(RoleSearchRequestDto model)
        {
            var isInRole = _securityUser.IsInRole("admin");

            var roleSpecification = new RoleSpecification(model, isInRole);

            var roleEntities = await _roleRepository.ListAsync(roleSpecification);
            var count = await _roleRepository.CountAsync(roleSpecification);
            return await PaginatedResult<RoleInfoResponseDto>.SuccessAsync(
                _mapper.Map<List<RoleInfoResponseDto>>(roleEntities),
                count,
                model.Page, model.Limit);
        }

        public async Task<Result<IList<RoleInfoResponseDto>>> QueryRolesAsync(RoleSearchRequestDto model)
        {
            var isInRole = _securityUser.IsInRole("admin");

            var roleSpecification = new RoleSpecification(model, isInRole);

            var roleEntities = await _roleRepository.ListAsync(roleSpecification);

            return await Result<IList<RoleInfoResponseDto>>.SuccessAsync(
                _mapper.Map<IList<RoleInfoResponseDto>>(roleEntities));
        }

        public async Task<Result<RoleInfoResponseDto>> GetRoleAsync(Guid id)
        {
            var roleEntity = await _roleRepository.GetByIdAsync(id);
            if (roleEntity == null)
            {
                return await Result<RoleInfoResponseDto>.FailAsync($"the role {id} is not found");
            }

            return await Result<RoleInfoResponseDto>.SuccessAsync(_mapper.Map<RoleInfoResponseDto>(roleEntity));
        }

        public async Task<Result<RoleInfoResponseDto>> CreateRoleAsync(RoleEditRequestDto model)
        {
            var roleEntity = _mapper.Map<RoleEntity>(model);
            roleEntity = await _roleRepository.AddAsync(roleEntity);
            return await Result<RoleInfoResponseDto>.SuccessAsync(_mapper.Map<RoleInfoResponseDto>(roleEntity));
        }

        public async Task<Result<RoleInfoResponseDto>> UpdateRoleAsync(Guid id, RoleEditRequestDto model)
        {
            var roleEntity = await _roleRepository.GetByIdAsync(id);
            if (roleEntity == null)
            {
                return await Result<RoleInfoResponseDto>.FailAsync($"the role {id} is not found");
            }

            _mapper.Map(model, roleEntity);

            await _roleRepository.UpdateAsync(roleEntity);

            return await Result<RoleInfoResponseDto>.SuccessAsync(_mapper.Map<RoleInfoResponseDto>(roleEntity));
        }

        public async Task<Result<RoleInfoResponseDto>> DeleteRoleAsync(Guid id)
        {
            var roleEntity = await _roleRepository.GetByIdAsync(id);
            if (roleEntity == null)
            {
                return await Result<RoleInfoResponseDto>.FailAsync($"the role {id} is not found");
            }

            await _roleRepository.DeleteAsync(roleEntity);

            return await Result<RoleInfoResponseDto>.SuccessAsync(_mapper.Map<RoleInfoResponseDto>(roleEntity));
        }

        public async Task<Result<IList<RoleClaimResponseDto>>> QueryPermissionsByRoleIdAsync(Guid id)
        {
            // var roleEntity = await _roleRepository.GetByIdAsync(id);
            // if (roleEntity == null)
            // {
            //     throw new NotFoundException($"the role {id} is not found");
            // }

            // await _roleRepository.EnsureCollectionLoadedAsync(roleEntity, i => i.Claims!);

            // if (roleEntity.Claims != null)
            // {
            //     return await Result<IList<RoleClaimResponseDto>>.SuccessAsync(
            //         _mapper.Map<List<RoleClaimResponseDto>>(roleEntity.Claims.ToList()));
            // }

            var roleClaimEntities = await _roleRepository.QueryClaimsByRoleAsync(id);

            return await Result<IList<RoleClaimResponseDto>>.SuccessAsync(
                _mapper.Map<IList<RoleClaimResponseDto>>(roleClaimEntities));
        }

        public async Task<Result<IList<RoleClaimResponseDto>>> UpdatePermissionsByRoleIdAsync(Guid id,
            List<string> model)
        {
            // var roleEntity = await _roleRepository.GetByIdAsync(id);
            // if (roleEntity != null)
            // {
            //     await _roleRepository.EnsureCollectionLoadedAsync(roleEntity, i => i.Claims!);
            //
            //     var addList = model.Where(i => roleEntity.Claims != null
            //                                    && (!roleEntity.Claims.Any(j =>
            //                                        j.ClaimType.Equals(ApplicationClaimTypes.Permission) &&
            //                                        j.ClaimValue.Equals(i)))).ToList();
            //
            //     var delList = roleEntity.Claims?.Where(i =>
            //         (!model.Any(j =>
            //             i.ClaimType.Equals(ApplicationClaimTypes.Permission) && i.ClaimValue.Equals(j)))).ToList();
            //
            //     if (addList.Any())
            //     {
            //         foreach (var item in addList)
            //         {
            //             roleEntity.Claims!.Add(new IdentityRoleClaim<Guid>()
            //             {
            //                 RoleId = id,
            //                 ClaimType = ApplicationClaimTypes.Permission,
            //                 ClaimValue = item
            //             });
            //         }
            //     }
            //
            //     if (delList != null && delList.Any())
            //     {
            //         foreach (var item in delList)
            //         {
            //             roleEntity.Claims!.Remove(item);
            //         }
            //     }
            //
            //     await _roleRepository.UpdateAsync(roleEntity);
            //
            //     return await Result<IList<RoleClaimResponseDto>>.SuccessAsync(
            //         _mapper.Map<IList<RoleClaimResponseDto>>(roleEntity.Claims));
            // }

            var roleClaimEntities = await _roleRepository.QueryClaimsByRoleAsync(id);

            var addList = model.Where(i => (!roleClaimEntities.Any(j =>
                j.ClaimType.Equals(ApplicationClaimTypes.Permission) &&
                j.ClaimValue.Equals(i)))).ToList();

            var delList = roleClaimEntities.Where(i =>
                (!model.Any(j =>
                    i.ClaimType.Equals(ApplicationClaimTypes.Permission) && i.ClaimValue.Equals(j)))).ToList();

            if (addList.Any())
            {
                foreach (var item in addList)
                {
                    await _roleRepository.AddRoleClaimAsync(new RoleClaimEntity()
                    {
                        RoleId = id,
                        ClaimType = ApplicationClaimTypes.Permission,
                        ClaimValue = item
                    });
                }
            }

            if (delList.Any())
            {
                foreach (var item in delList)
                {
                    await _roleRepository.RemoveRoleClaimAsync(item);
                }
            }

            await _roleRepository.SaveChangesAsync();

            return await Result<IList<RoleClaimResponseDto>>.SuccessAsync(data: null!);
        }

        public async Task<Tuple<Stream, string>> ExportAsync(RoleSearchRequestDto model)
        {
            var isInRole = _securityUser.IsInRole("admin");

            var fileName = $"RoleListExport_{_dateTimeProvider.GetCurrentDateTime():yyyyMMddHHmmss}.xlsx";
            var roleSpecification = new RoleSpecification(model, isInRole);
            var roleEntities = await _roleRepository.ListAsync(roleSpecification);

            var list = _mapper.Map<List<RoleInfoResponseDto>>(roleEntities);

            var stream = _excelProvider.WriteToStream(list, "Sheet1");

            return new Tuple<Stream, string>(stream, fileName);
        }

        public Task<Tuple<Stream, string>> ExportTemplateAsync()
        {
            var fileName = $"RoleTemplateExport_{_dateTimeProvider.GetCurrentDateTime():yyyyMMddHHmmss}.xlsx";

            var stream = _excelProvider.WriteToStream<RoleTemplateResponseDto>("Sheet1");

            return Task.FromResult(new Tuple<Stream, string>(stream, fileName));
        }

        public async Task<Result<IList<RoleImportResponseDto>>> ImportAsync(int importType, MemoryStream memoryStream)
        {
            var roleTemplateResponseDtos =
                _excelProvider.ReadToCollection<RoleTemplateResponseDto>(memoryStream);

            IList<RoleImportResponseDto> importDatas = new List<RoleImportResponseDto>();

            // 校验数据
            foreach (var item in roleTemplateResponseDtos)
            {
                var roleImportResponseDto = new RoleImportResponseDto(item);
                StringBuilder sb = new StringBuilder();
                if (string.IsNullOrEmpty(item.RoleCode))
                {
                    sb.Append("角色编码不能为空；");
                }

                if (string.IsNullOrEmpty(item.RoleName))
                {
                    sb.Append("角色名称不能为空；");
                }

                roleImportResponseDto.ErrorMessage = sb.ToString();

                importDatas.Add(roleImportResponseDto);
            }

            var hasError = importDatas.Any(i => !string.IsNullOrEmpty(i.ErrorMessage));
            if (!hasError)
            {
                var roleEntities = _mapper.Map<IList<RoleEntity>>(roleTemplateResponseDtos);

                await _roleRepository.AddRangeAsync(roleEntities);
            }

            return await Result<IList<RoleImportResponseDto>>.SuccessAsync(importDatas);
        }

        public async Task<PaginatedResult<UserInfoResponseDto>> QueryUsersByRoleIdAsync(Guid id,
            UserSearchRequestDto model)
        {
            // var userSpecification = new UserSpecification(model);
            // var roleEntities = await _userRepository.ListAsync(userSpecification);
            // var count = await _userRepository.CountAsync(userSpecification);
            // return PaginatedResult<UserInfoResponseDto>.Success(_mapper.Map<List<UserInfoResponseDto>>(roleEntities), count,
            //     model.Page, model.Limit);

            var result = await _userRepository.QueryByPageRoleAsync(id, model);

            return await PaginatedResult<UserInfoResponseDto>.SuccessAsync(
                _mapper.Map<List<UserInfoResponseDto>>(result.Item1),
                result.Item2,
                model.Page, model.Limit);
        }

        public async Task<Result<IList<UserInfoResponseDto>>> UpdateUsersByRoleIdAsync(Guid id, RoleOperateRequestDto model)
        {
            try
            {
                var userRoleEntities = await _roleRepository.QueryUserRolesByRoleAsync(id);

                var userEntities = await _userRepository.QueryByUserNamesAsync(model.UserNames);

                if (model.OperateType.Equals("Add"))
                {
                    var addList = userEntities.Where(i => userRoleEntities.All(j => j.UserId != i.Id)).ToList();

                    if (addList.Any())
                    {
                        foreach (var item in addList)
                        {
                            await _roleRepository.AddUserRoleAsync(new UserRoleEntity()
                            {
                                RoleId = id,
                                UserId = item.Id
                            });
                        }
                    }

                }
                else if (model.OperateType.Equals("Delete"))
                {

                    var delList = userRoleEntities.Where(i => userEntities.All(j => i.UserId == j.Id)).ToList();

                    if (delList.Any())
                    {
                        foreach (var item in delList)
                        {
                            await _roleRepository.RemoveUserRoleAsync(item);
                        }
                    }

                }
                
                await _roleRepository.SaveChangesAsync();

                return await Result<IList<UserInfoResponseDto>>.SuccessAsync(data: null!);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }
    }
}